/*
 * Copyright 2012 Alain Pannetrat (L1L1@gmx.com)
 * 
 * This file is part of cookie-miner.
 * 
 * cookie-miner is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 * 
 * cookie-miner is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License 
 * along with cookie-miner. If not, see http://www.gnu.org/licenses/.
 *
 * @version: $Id$
 *
 */
#ifndef HTTP_PACKET_H
#define HTTP_PACKET_H

#include <list>
#include <vector>
#include <string>
#include "bufio.h"
#include "log_facility.h"
#include <cstdlib>
#include <cstring>
#include "tcp.h"
#include "common.h"
#include "keyvalue.h"

class HttpPacket {
	public:

		class Headline {
			public:
				Headline() {}

				bool set(const std::string& line);
			
				bool set(const std::string& part0, 
					 const std::string& part1, 
					 const std::string& part2);

				std::string full() const;
				
				const std::string& part(int part) const;

				bool read_in(BufferIn* in);

				bool write_out(BufferOut* out) const { 
				    return out->write_line(full() + "\r\n"); }	
	
				void clear();
			private:
				std::string _headline_parts[3];

				DISALLOW_COPY_AND_ASSIGN(Headline);
		};

		class Headers {
			public:
				Headers() {}

				bool add_line(const std::string& keyval);
				bool erase(const std::string& s, unsigned index=0);
				unsigned exists(const std::string& s) const;

				bool set(const std::string& field, const std::string& value, unsigned index=0);
				bool set(const std::string& field, int value, unsigned index=0);

				KeyValueList::iterator begin() { return _headers.begin(); }
				KeyValueList::const_iterator begin() const { return _headers.begin(); }
				
				KeyValueList::iterator end() { return _headers.end(); }
				KeyValueList::const_iterator end() const { return _headers.end(); }

				KeyValueList::iterator find(const std::string& field, unsigned index=0);
				KeyValueList::const_iterator find(const std::string& field, unsigned index=0) const;
				const std::string& get(const std::string& field, unsigned index=0) const;
				int get_as_int(const std::string& field, unsigned index=0) const;

				KeyValueList::const_iterator match_word(const std::string& field, const std::string& word) const;
				
				bool read_in(BufferIn* in);
				bool write_out(BufferOut *out) const;

				void clear();
			private:
				KeyValueList _headers;

				DISALLOW_COPY_AND_ASSIGN(Headers);
		};

	 	class Timestamp 
		{
			public:
				Timestamp(unsigned sec=0, unsigned usec=0) { set(sec,usec); }
				void set(unsigned sec, unsigned usec)	{ ts_sec=sec; ts_usec=usec; }
				unsigned usec() const { return ts_usec; }
				void usec(unsigned val_usec) { ts_usec = val_usec; }
				unsigned sec() const { return ts_sec; }
				void sec(unsigned val_sec) { ts_sec = val_sec; }
			private:
				unsigned ts_sec;
				unsigned ts_usec;
		};
	
		HttpPacket(); 

		static HttpPacket* create() 	{ return new HttpPacket(); }

		void id(int packet_id)		{ _packet_id = packet_id; }
		int id() const 			{ return _packet_id; }

		void parent_id(int packet_id)	{ _parent_packet_id = packet_id; }
		int parent_id() const 		{ return _parent_packet_id; }

		void timestamp(const Timestamp &ts) 		{ _packet_timestamp = ts; }
		const Timestamp& timestamp() const		{ return _packet_timestamp; }

		void source(const SocketAddress& sa)		{ _source = sa; }	
		const SocketAddress& source() const 		{ return _source; }
		
		void destination(const SocketAddress &sa)	{ _destination = sa; }
		const SocketAddress& destination() const	{ return _destination; }

		const Headline& headline() const { return _headline; }
		Headline& headline() { return _headline; }

		const Headers& headers() const { return _headers; }
		Headers& headers() { return _headers; }

		bool content_read_in_write_out(BufferIn *in, BufferOut *out, bool no_content=false);
		bool content_read_in(BufferIn *in) { return content_read_in_write_out(in,NULL); }
		bool content_add(unsigned len, const unsigned char *content);
		bool content_add(const std::string& content) {
			return content_add(content.size(),(const unsigned char *)content.data()); }
		bool content_add(const char *content) { 
			return content_add((unsigned)strlen(content),(const unsigned char *)content); }
		unsigned content_length() const;
		const unsigned char *content_get() const;
		bool content_write_out(BufferOut *out) const;

		void content_length_limit(unsigned limit) 	{ _content_length_limit = limit; }
		unsigned content_length_limit() 		{ return _content_length_limit; }

		void log() const;

		void clear();

		~HttpPacket();
	private:
		Headline _headline;
		Headers _headers;

		unsigned _content_length_limit;
		unsigned char *_content;
		unsigned _content_size;
		unsigned _content_max;

		int	 	_packet_id;
		int	 	_parent_packet_id;
		Timestamp 	_packet_timestamp;
		SocketAddress	_source;
		SocketAddress 	_destination;
		//bool		_storage;

		static std::string _empty_string;

		DISALLOW_COPY_AND_ASSIGN(HttpPacket);
};

#include <sqlite3.h>
class HttpPacketDB {
	public:
		typedef enum {
			ITERATE_HEADER_AND_CONTENT,
			ITERATE_HEADER_ONLY
		} iterate_how;

		bool open(bool readonly);
		bool iterate(char *expression, 
			     bool(*iter_cb)(HttpPacket *, void *), 
			     void *params=NULL, 
			     iterate_how how=ITERATE_HEADER_AND_CONTENT);

		bool store(HttpPacket* packet);
		//bool load(HttpPacket* packet);
	        int top_id();
		void close();

		HttpPacketDB() : _dbhandle(NULL) {}
		~HttpPacketDB() { if (_dbhandle) close(); }
		static void set_file(const std::string& db) { _db_name = db; }
	private:
		static std::string _db_name;
		sqlite3* _dbhandle;
};

#endif
